package io.gitee.kotle.android.library.okhttp


import androidx.annotation.WorkerThread
import io.gitee.kotle.android.BaseGlobalConst
import io.gitee.kotle.android.utils.*
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import org.litepal.extension.findFirst


/**
 *
 *
 */
abstract class BaseOkHttpApi {

    /**
     * 获取对象
     */
    open fun getOkHttpClient() = BaseGlobalConst.okHttpClient

    /**
     * baseUrl
     */
    abstract fun getBaseUrl(): String

    /**
     * 发起请求
     * [String] path
     */
    suspend inline fun <reified T> String.request(
        params: Any?,
        requestBody: RequestBody?,
        cache: Boolean,
        customType: GsonParameterizedType<T>? = null,
    ): T {
        val builder = onRequestBuild(this, params, requestBody)
        val request = builder.build()
        val resultStr = withIoThread {
            onTransformResponse(request, request.awaitHttpResponse(getOkHttpClient()))
        }
        if (cache) {
            onCacheOkHttp(resultStr, request, params)
        }
        return resultStr.formJsonString(customType)
    }

    /**
     * 缓存okHttp
     */
    open suspend fun onCacheOkHttp(resultStr: String, request: Request, params: Any?) {
        withIoThread {
            ignoreError {
                KotleOkHttpCacheTable().apply {
                    this.url = request.url.toString()
                    this.params = params?.toJsonString()
                    this.content = resultStr
                    this.heads = request.headers.toMultimap().toJsonString()
                    this.method = request.method
                }.cacheOrUpdateTyphurOkHttp()
            }
        }
    }

    open suspend fun KotleOkHttpCacheTable.cacheOrUpdateTyphurOkHttp() {
        val table = this
        val find = table.url.findOkHttpCacheFromDb(table.params, table.urlId)
        if (find == null) {
            table.createTime = System.currentTimeMillis()
            table.updateTime = table.createTime
            table.save()
        } else {
            find.updateColumn {
                it.put("urlId", table.urlId)
                it.put("url", table.url)
                it.put("heads", table.heads)
                it.put("params", table.params)
                it.put("method", table.method)
                it.put("content", table.content)
                it.put("updateTime", System.currentTimeMillis())
            }
        }
    }

    /**
     * 查询缓存
     */
    open suspend fun String.findOkHttpCacheFromDb(
        params: Any? = null,
        urlId: String = KotleOkHttpCacheTable.EMPTY_URL_ID
    ): KotleOkHttpCacheTable? {
        return withIoThread {
            ignoreError {
                if (params == null)
                    sqlite.where("url=? and urlId=?", this, urlId)
                        .findFirst<KotleOkHttpCacheTable>()
                else
                    sqlite.where(
                        "url=? and urlId=? and params=?",
                        this,
                        urlId,
                        params.toJsonString()
                    ).findFirst<KotleOkHttpCacheTable>()
            }
        }
    }

    /**
     * 对字符串最转换
     */
    @WorkerThread
    open fun onTransformResponse(request: Request, response: Response): String {
        return response.fromJson()
    }

    /**
     * 获取完整的url
     */
    open fun getRequestUrl(baseUrl: String, path: String): String {
        return "${baseUrl.trimEnd('/')}/${path.trimStart('/')}"
    }

    /**
     * 处理请求头
     */
    open fun onRequestBuild(
        path: String,
        params: Any?,
        requestBody: RequestBody?,
    ): Request.Builder {
        log { "请求参数（$params）：${params?.toJsonString()}" }
        val builder = Request.Builder()
            .url(getRequestUrl(getBaseUrl(), path))
        if (requestBody != null) {
            builder.post(requestBody)
        }
        return builder
    }
}